
package combat.dudes.server.protocol.implementation;

import java.rmi.RemoteException;
import java.util.ArrayList;

import combat.dudes.DudesConfig.SharedVars;
import combat.dudes.DudesFunctions;
import combat.dudes.protocol.data.DoublePoint;
import combat.dudes.protocol.data.PhysicalObject;
import combat.dudes.protocol.data.RemoteList;
import combat.dudes.protocol.interfaces.OnboardSystemInt;
import combat.dudes.protocol.interfaces.OnboardWeaponSystemInt;
import combat.dudes.protocol.interfaces.OrderInt;
import combat.dudes.protocol.interfaces.VehicleInt;
import combat.dudes.protocol.types.PhysicalObjectType;
import combat.dudes.protocol.types.SensorSystemType;
import combat.dudes.protocol.types.VehicleType;
import combat.dudes.protocol.types.WeaponSystemType;
import combat.dudes.server.ServerApp;


/**
 * The vehicle class, containing all information of a vehicle (e.g. a ship).
 * @author Laurens Andriessen
 * @author Gerard Krombeen
 * @author Jesper Keijzer
 */
public class Vehicle extends PhysicalObject implements VehicleInt {

	private static final long serialVersionUID = 1L;

	// [ Inherited from PhysicalObject ]
	// String name
	// DoublePoint position
	// int altitude
	// double direction
	// double speed
	private double fuel = 0.0;
	private int health = 100;
	private Boolean locked = false;
	private ArrayList<OnboardSystemInt> onboardSystems = new ArrayList<OnboardSystemInt>();
	private ArrayList<OrderInt> orders = new ArrayList<OrderInt>();
	private VehicleType vehicleType = VehicleType.UNKNOWN;

	/**
	 * Constructor for making a new Vehicle
	 */
	public Vehicle() {
		setType(PhysicalObjectType.VEHICLE);
	}

	/**
	 * Constructor for making a new Vehicle
	 * @param fuel
	 * @param type
	 * @param name
	 * @param position
	 * @param altitude
	 * @param direction
	 * @param speed
	 * @param fuel
	 * @param health
	 * @param locked
	 * @param orders
	 */
	public Vehicle(VehicleType vehicleType, String name, DoublePoint position, int altitude, double direction, double speed, double fuel, int health, Boolean locked, ArrayList<OrderInt> orders) {
		super(PhysicalObjectType.VEHICLE, name, position, altitude, direction, speed);
		this.vehicleType = vehicleType;
		this.fuel = fuel;
		this.health = health;
		this.locked = locked;

		if(orders != null)
			this.orders = orders;

		switch(vehicleType) {
			case UNKNOWN:
				super.setAltitude(0);
				break;
			case CONVOY:
				super.setAltitude(0);
				// Assign SensorSystems
				onboardSystems.add(new OnboardSensorSystem(SharedVars.getMaxDistance(SensorSystemType.RADAR), SensorSystemType.RADAR));
				onboardSystems.add(new OnboardSensorSystem(SharedVars.getMaxDistance(SensorSystemType.SIGHT), SensorSystemType.SIGHT));
				break;
			case FRIGATE:
				super.setAltitude(0);
				// Assign WeaponSystems
				onboardSystems.add(new OnboardWeaponSystem(SharedVars.getDefaultAmmo(WeaponSystemType.GUIDED_MISSILELAUNCHER), WeaponSystemType.GUIDED_MISSILELAUNCHER));
				onboardSystems.add(new OnboardWeaponSystem(SharedVars.getDefaultAmmo(WeaponSystemType.GOALKEEPER), WeaponSystemType.GOALKEEPER));
				onboardSystems.add(new OnboardWeaponSystem(SharedVars.getDefaultAmmo(WeaponSystemType.TORPEDOLAUNCHER), WeaponSystemType.TORPEDOLAUNCHER));
				onboardSystems.add(new OnboardWeaponSystem(SharedVars.getDefaultAmmo(WeaponSystemType.UNGUIDED_MISSILELAUNCHER), WeaponSystemType.UNGUIDED_MISSILELAUNCHER));
				// Assign SensorSystems
				onboardSystems.add(new OnboardSensorSystem(SharedVars.getMaxDistance(SensorSystemType.RADAR), SensorSystemType.RADAR));
				break;
			case SUBMARINE:
				super.setAltitude(-1);
				// Assign WeaponSystems
				onboardSystems.add(new OnboardWeaponSystem(SharedVars.getDefaultAmmo(WeaponSystemType.TORPEDOLAUNCHER), WeaponSystemType.TORPEDOLAUNCHER));
				// Assign SensorSystems
				onboardSystems.add(new OnboardSensorSystem(SharedVars.getMaxDistance(SensorSystemType.SONAR), SensorSystemType.SONAR));
				break;
			default:
				super.setAltitude(0);
				break;
		}
	}

	@Override
	public double getFuel() {
		return fuel;
	}
	@Override
	public void setFuel(double fuel) {
		if(fuel < 0.0)
			fuel = 0.0;
		this.fuel = fuel;
	}

	@Override
	public int getHealth() {
		return health;
	}
	@Override
	public void setHealth(int health) {
		if(health < 0)
			health = 0;
		this.health = health;
	}

	@Override
	public Boolean getLocked() {
		return locked;
	}
	@Override
	public void setLocked(Boolean locked) {
		this.locked = locked;
	}

	@Override
	public ArrayList<OnboardSystemInt> getOnboardSystems() {
		return onboardSystems;
	}
	@Override
	public void setOnboardSystems(ArrayList<OnboardSystemInt> onboardSystems) {
		this.onboardSystems = onboardSystems;
	}

	@Override
	public ArrayList<OrderInt> getOrders() {
		return orders;
	}
	@Override
	public void setOrders(ArrayList<OrderInt> orders) {
		this.orders = orders;
	}

	@Override
	public VehicleType getVehicleType() {
		return (vehicleType == null) ? VehicleType.UNKNOWN : vehicleType;
	}
	@Override
	public void setVehicleType(VehicleType vehicleType) {
		this.vehicleType = vehicleType;
	}

	// ------------------------------------------

	@Override
	public void lock() {
		this.locked = true;
	}
	@Override
	public void unlock() {
		this.locked = false;
	}

	@Override
	public void orderMove(int orderID, Object target, double speed) {
		if(getHealth() > 10) {
			OrderMovement newMovement = new OrderMovement(target, speed);
			this.orders.add(newMovement);
		}
	}
	@Override
	public void orderAttack(int orderID, Object target, OnboardWeaponSystemInt system) {
		if(DudesFunctions.Network.isProxy(system)) system = Simulation.instance().findWeaponSystem(system);
		if(system.getAmmo() > 0) {
			OrderAttack newAttack = new OrderAttack(target, system);
			this.orders.add(newAttack);
			system.fire(target);
		}
	}
	@Override
	public void orderCancel(OrderInt order) {
		order.setOrderID(-1);
	}

	public void orderRemove(Order order) {
		orders.remove(order);
	}

	@Override
	public RemoteList getOnboardSystems_Remote() {
		try {
			return new RemoteList(getOnboardSystems());
		} catch(RemoteException e) {
			ServerApp.onError("@Vehicle.java, getOnboardSystems_Remote()", e, false);
		}
		return new RemoteList();
	}

	@Override
	public RemoteList getOrders_Remote() {
		try {
			return new RemoteList(getOrders());
		} catch(RemoteException e) {
			ServerApp.onError("@Vehicle.java, getOrders_Remote()", e, false);
		}
		return new RemoteList();
	}

}
